package com.xinxing.learning.datasource.aop;

import com.xinxing.learning.datasource.annotation.DbKey;
import com.xinxing.learning.datasource.config.DynamicDataSource;
import com.xinxing.learning.datasource.context.DynamicContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Objects;

@Aspect
@Slf4j
@Component
public class DynamicDataSourceAspect {

    @Pointcut("@annotation(com.xinxing.learning.datasource.annotation.DynamicDataSource) " +
            "|| @within(com.xinxing.learning.datasource.annotation.DynamicDataSource)")
    public void dynamicDataSourcePointCut() {

    }

    @Around("dynamicDataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        String dbKey = getDbKey(point);
        if (StringUtils.isNotBlank(dbKey))
            DynamicDataSource.setDataSource(dbKey);
        try {
            return point.proceed();
        } finally {
            DynamicContextHolder.poll();
        }
    }

    private String getDbKey(ProceedingJoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Object[] args = point.getArgs();
        String value = null;
        // 参数注解，1维是参数，2维是注解
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        for (int i = 0; i < parameterAnnotations.length; i++) {
            Object param = args[i];
            Annotation[] paramAnnotation = parameterAnnotations[i];
            if (Objects.isNull(param) || paramAnnotation.length == 0) {
                continue;
            }

            for (Annotation annotation : paramAnnotation) {
                if (Objects.equals(annotation.annotationType(), DbKey.class)) {
                    value = param.toString();
                    break;
                }
            }
        }

        return value;
    }
}
